package com.test.random.server.port.config;

import com.test.random.server.port.constants.RandomServerPortConstant;
import com.test.random.server.port.poperties.DefaultServerPortProperties;
import com.test.random.server.port.poperties.RandomServerPortProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.SocketUtils;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName RandomServerPortConfig
 * @Description TODO
 * @Author jhwang
 * @Date 2021/9/12 19:59
 * @Version 1.0.0
 */
@Configuration
@ComponentScan(basePackages = {"com.test.random.server.port"})
@EnableConfigurationProperties(value = {DefaultServerPortProperties.class, RandomServerPortProperties.class})
public class RandomServerPortConfig {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final DefaultServerPortProperties defaultProperties;
    private final RandomServerPortProperties randomProperties;

    public RandomServerPortConfig(DefaultServerPortProperties defaultServerPortProperties,
                                  RandomServerPortProperties randomServerPortProperties) {

        this.defaultProperties = defaultServerPortProperties;
        this.randomProperties = randomServerPortProperties;
    }

    /**
     * boot 2.x 版本
     */
    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> containerCustomizer() {
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                /* when config server.port= 0，and scf.random.server.port.open = true  , then open ... */
                try {
                    if (defaultProperties.getPort().compareTo(RandomServerPortConstant.DEFAULT_SERVER_PORT) == 0
                            && Boolean.TRUE.equals(randomProperties.getOpen())) {

                        int port, retry = 0;
                        Set<Integer> denyPort = Arrays.stream(randomProperties.getDenyPort().split(",")).map(p -> Integer.valueOf(p)).collect(Collectors.toSet());
                        do {
                            port = SocketUtils.findAvailableTcpPort(randomProperties.getMinPort(), randomProperties.getMaxPort());
                            retry++;
                        } while (denyPort.contains(port) && randomProperties.getRetry().compareTo(retry) > 0);
                        port = denyPort.contains(port) ? 0 : port;
                        factory.setPort(port);
                        System.getProperties().put("server.port", port);
                        logger.info("init scf.random.port : {} ", port);
                    }
                } catch (Exception e) {
                    logger.error("init scf.random.port error {}", e);
                }
            }
        };
    }

    /**
     * boot 1.x 版本
     */

//    @Bean
//    public EmbeddedServletContainerCustomizer containerCustomizer() {
//        return new EmbeddedServletContainerCustomizer() {
//            @Override
//            public void customize(ConfigurableEmbeddedServletContainer container) {
//                /* when config server.port= 0，and scf.random.server.port.open = true  , then open ... */
//                try {
//                    if (defaultProperties.getPort().compareTo(RandomServerPortConstant.DEFAULT_SERVER_PORT) == 0
//                            && Boolean.TRUE.equals(randomProperties.getOpen())) {
//
//                        int port, retry = 0;
//                        Set<Integer> denyPort = Arrays.stream(randomProperties.getDenyPort().split(",")).map(p -> Integer.valueOf(p)).collect(Collectors.toSet());
//                        do {
//                            port = SocketUtils.findAvailableTcpPort(randomProperties.getMinPort(), randomProperties.getMaxPort());
//                            retry++;
//                        } while (denyPort.contains(port) && randomProperties.getRetry().compareTo(retry) > 0);
//                        port = denyPort.contains(port) ? 0 : port;
//                        container.setPort(port);
//                        System.getProperties().put("server.port", port);
//                        logger.info("init scf.random.port : {} ", port);
//                    }
//                } catch (Exception e) {
//                    logger.error("init scf.random.port error {}", e);
//                }
//
//            }
//        };
//    }
//


}
